/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Eng_Ahmed Salama
 */
/*Imports the java.awt package classes.*/
import java.awt.List;
import java.awt.*;
/*Imports the java.awt.event package classes.*/
import java.awt.event.*;
/*Imports java.io package classes.*/
//import java.io.PrintStream;
/*Imports java.util package classes.*/
import java.util.*;
/*Imports the javax.swing package classes.*/
import javax.swing.*;
/*Imports the java.swing.text package classes.*/
import javax.swing.text.*;
/*
Class ChatClient - Creates the main window of the chat application. This window contains a text
pane to display the messages and list box to display the user list.
   Methods:
      - prepareAllStyles()
      - run()
      - itemStateChanged()
      - actionPerformed()
      - con()
      - AddUser()
   Class
      - ListofUser
      - PrivateChat
      - BroadcastChat
*/
public class ChatClient extends JFrame implements ActionListener, Runnable, ItemListener
{
   /*Declares the AWT and Swing components.*/
   JPanel paneMain;
   JPanel paneLeft;
   JPanel paneRight;
   JPanel paneBottom;
   JLabel welcomeLabel;
   JLabel listLabel;
   JLabel pMsgLabel;
   JLabel bMsgLabel;
   JTextField msgText;
   JTextArea pArea;
   JTextField empty;
   List clientList;
   JScrollPane pAreaScroll;
   JScrollPane listScroll;
   JButton sendButton;
   JButton privateButton;
   JButton logoutButton;
   JTextField listText;
   SimpleAttributeSet aset;
   AttributeSet current;
   Hashtable ht = null;
   DefaultStyledDocument doc = null;
   JTextPane tp = null;
   /*Declares the object of the Thread class.*/
   Thread thread;
   Thread t;
   Thread th;
   /*Declares the static string to set the text pane attributes.*/
   final String NORMALBLUE = "NormalBlue";
   final String BOLDBLUE = "BoldBlue";
   final String NORMALBLACK = "NormalBlack";
   final String BOLDGREEN = "BoldGreen";
   final String NORMALRED = "NormalRed";
   final String ITALICRED = "ItalicRed";
   /*Declares the objects of the String class.*/
   String nameStr1 = null;
   String msgStr1 = null;
   String nameStr2 = null;
   String msgStr2 = null;
   String str3 = null;
   String str4 = null;
   String str5 = null;
   String str6 = null;
   String msg;
   String user;
   int value;
   int count=0;
   int i;
   /*Creates the object of the PrivateChat class.*/
   PrivateChat Pchat = new PrivateChat();
   /*Creates the object of the BroadcastChat class.*/
   BroadcastChat Achat = new BroadcastChat();
   /*Creates the object of the ListofUser class.*/
   ListofUser UL=new ListofUser();
   /*Creates the object of the CClient class.*/
   CClient CC = null;
   /*Defines the default constructor.*/
   public ChatClient()
   {
      setSize(800, 400);
      setTitle("Chat Client");
      setResizable(false);
      paneMain = new JPanel();
      paneMain.setLayout(new BorderLayout());
      getContentPane().add(paneMain);
      paneLeft = new JPanel();
      paneLeft.setLayout(new BorderLayout());
      doc = new DefaultStyledDocument();
      ht = new Hashtable();
      tp = new JTextPane(doc)
      {
         public void paintComponent(Graphics g)
         {
         super.paintComponent(g);
         }
         public void paint(Graphics g)
         {
            super.paint(g);
         }
      };
      tp.setFont(new Font("Verdana", Font.PLAIN, 12));
      tp.setEditable(false);
      pAreaScroll = new JScrollPane(tp);
      paneLeft.add(pAreaScroll, BorderLayout.CENTER);
      paneMain.add(paneLeft, BorderLayout.CENTER);
      paneRight = new JPanel();
      paneRight.setLayout(new BorderLayout());
      listLabel = new JLabel("User List");
      listText = new JTextField(10);
      listText.setVisible(false);
      clientList = new List(3);
      clientList.addActionListener(this);
      clientList.addItemListener(this);
      clientList.select(0);
      listScroll = new JScrollPane(clientList);
      paneRight.add(listText, BorderLayout.SOUTH);
      paneRight.add(listLabel, BorderLayout.NORTH);
      paneRight.add(listScroll, BorderLayout.CENTER);
      paneMain.add(paneRight, BorderLayout.EAST);
      paneBottom = new JPanel();
      paneBottom.setLayout(new FlowLayout());
      msgText = new JTextField(33);
      msgText.requestFocus();
      msgText.addActionListener(this);
      msgText.setFont(new Font("Verdana",Font.PLAIN,14));
      sendButton = new JButton("Send");
      privateButton = new JButton("Private Message");
      logoutButton = new JButton("Logout");
      empty = new JTextField(10);
      paneBottom.add(msgText);
      paneBottom.add(sendButton);
      paneBottom.add(privateButton);
      paneBottom.add(logoutButton);
      paneBottom.add(empty);
      paneMain.add(paneBottom, BorderLayout.SOUTH);
      privateButton.addActionListener(this);
      sendButton.addActionListener(this);
      logoutButton.addActionListener(this);
      prepareAllStyles();
      t = new Thread(this);
      /*
         addWindowListener - It contains a windowClosing() method.
         windowClosing: It is called when the user clicks the cancel button of the Window. It _
         closes the main window.
            Parameter: we- Object of WindowEvent class.
            Return Value: NA
      */
      addWindowListener(new WindowAdapter()
      {
         public void windowClosing(WindowEvent we)
         {
            value = JOptionPane.showConfirmDialog(null, "Are you sure you want to close the chat application?", "Close", JOptionPane.YES_NO_OPTION);
            if(value == 0)
            {
               try
               {
                  /*Calls the sendBroadMsg() method to inform all the users.*/
                  CC.sendBroadMsg(user + "* has left the chat session." + "+REMOVE");
                  System.exit(0);
               }
               catch(Exception e){}
            }
            else if(value == 1)
            {
            }
         }
      });
   }
/*Defines the prepareAllStyles() method that set the text attribute values.*/
public void prepareAllStyles()
   {
      aset = new SimpleAttributeSet();
      StyleConstants.setForeground(aset,Color.blue);
      StyleConstants.setFontSize(aset,12);
      StyleConstants.setFontFamily(aset,"Verdana");
      ht.put(NORMALBLUE,aset);
      aset = new SimpleAttributeSet();
      StyleConstants.setForeground(aset,Color.blue);
      StyleConstants.setFontSize(aset,12);
      StyleConstants.setFontFamily(aset,"Verdana");
      StyleConstants.setBold(aset, true);
      ht.put(BOLDBLUE,aset);
      aset = new SimpleAttributeSet();
      StyleConstants.setForeground(aset,Color.black);
      StyleConstants.setFontSize(aset,12);
      StyleConstants.setFontFamily(aset,"Verdana");
      ht.put(NORMALBLACK,aset);
      aset = new SimpleAttributeSet();
      StyleConstants.setForeground(aset, new Color(0, 128, 0));
      StyleConstants.setFontSize(aset,12);
      StyleConstants.setFontFamily(aset,"Verdana");
      StyleConstants.setBold(aset, true);
      ht.put(BOLDGREEN,aset);
      aset = new SimpleAttributeSet();
      StyleConstants.setForeground(aset,Color.red);
      StyleConstants.setFontSize(aset,12);
      StyleConstants.setFontFamily(aset,"Verdana");
      ht.put(NORMALRED,aset);
      aset = new SimpleAttributeSet();
      StyleConstants.setForeground(aset,Color.red);
      StyleConstants.setFontSize(aset,12);
      StyleConstants.setFontFamily(aset,"Verdana");
      StyleConstants.setItalic(aset, true);
      ht.put(ITALICRED,aset);
   }
   /*
itemStateChanged() - This method is called when the end user selects the user name from the user list.
   Parameters:	ae: Represent an object of the ActionEvent class that contains the details of the event.
      Return Value: NA
   */
   public void itemStateChanged(ItemEvent ie)
   {
      if(ie.getSource() == clientList)
      {
listText.setText(clientList.getSelectedItem());
         i = clientList.getSelectedIndex();
      }
   }
   /*
      actionPerformed() - This method is called when the end user clicks any button.
         Parameters:	ae: Represent an object of the ActionEvent class that contains the details
      of the event.
      Return Value: NA
   */
   public void actionPerformed(ActionEvent ae)
   {
      /*
         This section is executed when the end user clicks the Private Message button of the application.
      */
      if(ae.getSource() == privateButton)
      {
         try
         {
if(listText.getText().equals("*" + user))
            {
               JOptionPane.showMessageDialog(null, "You cannot send private message to _ yourself!", "Error", JOptionPane.ERROR_MESSAGE);
            }
            else
            {
               current = (AttributeSet)ht.get(BOLDBLUE);
               doc.insertString(doc.getLength(), "To " + listText.getText() + ": " ,current);
               current = (AttributeSet)ht.get(NORMALBLACK);
               doc.insertString(doc.getLength(), msgText.getText() +  "\n" ,current);
               Point pt1=tp.getLocation();
               Point pt2=new Point((int)(0),(int)(tp.getBounds().getHeight()));
               pAreaScroll.getViewport().setViewPosition(pt2);
            }
         }
catch(Exception e) {}
if(msgText.getText().trim().equals(""))
         {
         }
         else
         {
            /*Calls the sendPrivateMessage() method to send the private message.*/
            CC.sendPrivateMessage(msgText.getText().trim(),listText.getText());
            msgText.setText("");
         }
      }
      /*
This section is executed, when the end user clicks the Send button of the application.
      */
      else if(ae.getSource() == sendButton)
      {
         if(msgText.getText().trim().equals(""))
         {
         }
         else
         {
            /*Calls the sendBroadMsg() method to send the broadcast message.*/
            CC.sendBroadMsg(msgText.getText().trim() + "+MSG");
            msgText.setText("");
         }
      }
      /*
This section is executed, when the end user clicks the Logout button of the application.
      */
      else if(ae.getSource() == logoutButton)
      {
         value = JOptionPane.showConfirmDialog(null, "Are you sure you want to logout?", "Logout",
         JOptionPane.YES_NO_OPTION);
         if(value == 0)
         {
         try
         {
         /*Calls the sendBroadMsg() method to inform the end user has left the chat session.*/
         CC.sendBroadMsg(user + "* has left the chat session." + "+REMOVE");
         System.exit(0);
            }
            catch(Exception e){}
         }
         else if(value == 1)
         {
         }
      }
      /*
This section is executed, when the end user enter the sending text and press the enter button
from the keyboard.
      */
      else if(ae.getSource() == msgText)
      {
/*Calls the sendBroadMsg() method to send the broadcast message.*/
CC.sendBroadMsg(msgText.getText().trim() + "+MSG");
         msgText.setText("");
      }
   }
/*Implementation of con() method. This method establishes the connection between client and server.*/
public void con(String userName, String pwd, String ipAdd)
   {
      user = userName;
      CC = new CClient();
      /*Calls the addMessager() method of the CClient class.*/
      CC.addMessager(UL , Achat, Pchat);
      try
      {
         /*Calls the connect() method of the CClient class.*/
         CC.connect(userName, pwd, ipAdd);
      }
      catch(Exception e)
      {
         JOptionPane.showMessageDialog(null, "Unable to connect the server!", "Error",
         JOptionPane.ERROR_MESSAGE);
         ChatLogin cl = new ChatLogin();
         cl.show();
         this.setVisible(false);
         return;
      }
setTitle("Chat Application - " + userName);
/*Starts the thread to send to inform all the users.*/
      try
      {
         count = 1;
         t = new Thread(this);
         t.setPriority(Thread.MAX_PRIORITY);
         t.sleep(100);
         t.start();
      }
      catch(Exception e){};
/*Starts the thread to display the user list.*/
      try
      {
         count = 2;
         thread = new Thread(this);
         thread.sleep(100);
         thread.start();
      }
      catch(Exception e){}
      this.show();
      tp.repaint();
   }
/*Creates the class to display the user list.*/
   class ListofUser implements Messager
   {
      public void message(String m)
      {
         clientList.clear();
         AddUser(m);
         clientList.select(i);

      }
   };
/*Creates the class to send the private message.*/
class PrivateChat implements Messager
   {
      public void message(String m)
      {
         try
         {
            /*Inserts text in the text pane with the specified attributes.*/
            m=m.substring(0,m.length()-1);
            StringTokenizer st1 = new StringTokenizer(m, ":");
            nameStr1 = st1.nextToken();
            msgStr1 = st1.nextToken();
            current = (AttributeSet)ht.get(BOLDBLUE);
            doc.insertString(doc.getLength(), "From " + nameStr1 + ": ", current);
            current = (AttributeSet)ht.get(NORMALBLACK);
            doc.insertString(doc.getLength(), msgStr1 + "\n" , current);
            Point pt1=tp.getLocation();
            Point pt2=new Point((int)(0),(int)(tp.getBounds().getHeight()));
            pAreaScroll.getViewport().setViewPosition(pt2);
         }
         catch(Exception e){}
         tp.repaint();
      }
   };
/*Creates the class to send the broadcast message.*/
   class BroadcastChat implements Messager
   {
      public void message(String m)
      {
         try
         {
            /*Inserts text in the text pane with the specified attributes.*/
            StringTokenizer st2 = new StringTokenizer(m, ":");
            nameStr2 = st2.nextToken();
            msgStr2 = st2.nextToken();
            StringTokenizer st3 = new StringTokenizer(msgStr2, "+");
            str3 = st3.nextToken();
            str4 = st3.nextToken();
            if(str4.equals("ADD"))
            {
               StringTokenizer st4 = new StringTokenizer(str3, "*");
               str5 = st4.nextToken();
               str6 = st4.nextToken();
               if(str5.equals(user))
               {
                  try
               {
                  msg = "Welcome to chat session!";
                  current = (AttributeSet)ht.get(BOLDBLUE);
                  tp.setCharacterAttributes(current,true);
                  doc.insertString(doc.getLength(),  msg + "\n",current);
               }
               catch(Exception e){}
               }
               else
               {
                  try
                  {
                     current = (AttributeSet)ht.get(ITALICRED);
                     doc.insertString(doc.getLength(), str5 + str6 + "\n",current);
                     Point pt1=tp.getLocation();
                     Point pt2=new Point((int)(0),(int)(tp.getBounds().getHeight()));
                     pAreaScroll.getViewport().setViewPosition(pt2);
                  }
               catch(Exception e){}
               }
            }
else if(str4.equals("REMOVE"))
            {
               StringTokenizer st4 = new StringTokenizer(str3, "*");
               str5 = st4.nextToken();
               str6 = st4.nextToken();
               if(str5.equals(user))
               {
                  try
                  {
                     msg = "You have successfully logged out from this chat session.";
                     current = (AttributeSet)ht.get(ITALICRED);
                     doc.insertString(doc.getLength(), msg + "\n",current);
                     Point pt1=tp.getLocation();
                     Point pt2=new Point((int)(0),(int)(tp.getBounds().getHeight()));
                     pAreaScroll.getViewport().setViewPosition(pt2);
                  }
               catch(Exception e){}
               }
               else
               {
                  try
                  {
                     current = (AttributeSet)ht.get(ITALICRED);
                     doc.insertString(doc.getLength(), str5 + str6 + "\n",current);
                     Point pt1=tp.getLocation();
                     Point pt2=new Point((int)(0),(int)(tp.getBounds().getHeight()));
                     pAreaScroll.getViewport().setViewPosition(pt2);
                  }
               catch(Exception e){}
               }
            }
            else if (str4.equals("MSG"))
            {
               try
               {
                  current = (AttributeSet)ht.get(BOLDGREEN);
                  doc.insertString(doc.getLength(), nameStr2 + ": " , current);
                  current = (AttributeSet)ht.get(NORMALBLUE);
                  doc.insertString(doc.getLength(), str3 + "\n",current);
                  Point pt1=tp.getLocation();
                  Point pt2=new Point((int)(0),(int)(tp.getBounds().getHeight()));
                  pAreaScroll.getViewport().setViewPosition(pt2);
               }
               catch(Exception e){}
            }
         }
         catch (Exception ex) {}
         tp.repaint();
      }
   };
/*Creates the class to add a new end user into the user list.*/
private void AddUser(String s)
   {
      String tmp="";
      byte b[]=s.getBytes();
      if(s.length()>1)
       {
         for(int x=1;x<b.length;x++)
         {
            if(b[x]==31)
            {
               if(tmp.equals(user))
               {
                  clientList.add("*"+tmp);
               }
               else
               {
                  clientList.add(tmp);
               }
               tmp="";
            }
            else
            tmp+=(char)b[x];
         }
      }
   };
/*This method is invoked when thread is started.*/
public void run()
   {
      if(count == 1)
      {
         /*Calls the sendBroadMsg() to inform all the end users.*/
         CC.sendBroadMsg(user + "* has joined the chat session." + "+ADD");
      }
      else if(count == 2)
      {
         while(true)
         {
            try
            {
               /*Calls the sendListMsg() method to display the list of users.*/
               CC.sendListMsg("");
               Thread.sleep(5000);
            }
catch(Exception ee){ee.printStackTrace();}
         }
      }
   }
}

